/*
 * Tencent is pleased to support the open source community by making IoT Hub
 available.
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.

 * Licensed under the MIT License (the "License"); you may not use this file
 except in
 * compliance with the License. You may obtain a copy of the License at
 * http://opensource.org/licenses/MIT

 * Unless required by applicable law or agreed to in writing, software
 distributed under the License is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND,
 * either express or implied. See the License for the specific language
 governing permissions and
 * limitations under the License.
 *
 */

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "qcloud_iot_export.h"
#include "qcloud_iot_import.h"
#include "utils_getopt.h"

#include "ql_fs.h"
#include "ql_rtos.h"
#include "ql_data_call.h"
#include "ql_application.h"
#include "sockets.h"
#include "ql_dev.h"

#define PROFILE_IDX 1

#ifdef AUTH_MODE_CERT
/* NULL cert file */
#define QCLOUD_IOT_NULL_CERT_FILENAME "YOUR_DEVICE_CERT_FILE_NAME"
/* NULL key file */
#define QCLOUD_IOT_NULL_KEY_FILENAME "YOUR_DEVICE_PRIVATE_KEY_FILE_NAME"
#else
/* NULL device secret */
#define QCLOUD_IOT_NULL_DEVICE_SECRET "YOUR_IOT_PSK"
#endif

static void main_entry(void *argv)
{
    int        ret;
    DeviceInfo sDevInfo;
    bool       infoNullFlag = false;

    // init log level
    IOT_Log_Set_Level(eLOG_DEBUG);

    memset((char *)&sDevInfo, 0, sizeof(DeviceInfo));
    ret = HAL_GetDevInfo(&sDevInfo);

#ifndef GATEWAY_ENABLED
    sDevInfo.dev_type = eCOMMON_DEV;
#else
    sDevInfo.dev_type = eGW_SUB_DEV;
#endif

#ifdef AUTH_MODE_CERT
    /* just demo the cert/key files are empty */
    if (!strcmp(sDevInfo.dev_cert_file_name, QCLOUD_IOT_NULL_CERT_FILENAME) ||
        !strcmp(sDevInfo.dev_key_file_name, QCLOUD_IOT_NULL_KEY_FILENAME)) {
        Log_d("dev Cert not exist!");
        infoNullFlag = true;
    } else {
        Log_d("dev Cert exist");
    }
#else
    /* just demo the PSK is empty */
    if (!strcmp(sDevInfo.device_secret, QCLOUD_IOT_NULL_DEVICE_SECRET)) {
        Log_d("dev psk not exist!");
        infoNullFlag = true;
    } else {
        Log_d("dev psk exist");
    }
#endif

    /* device cert/key files or PSK is empty, do dynamic register to fetch */
    if (infoNullFlag) {
        if (QCLOUD_RET_SUCCESS == IOT_DynReg_Device(&sDevInfo)) {
            ret = HAL_SetDevInfo(&sDevInfo);
            if (QCLOUD_RET_SUCCESS != ret) {
                Log_e("devices info save fail");
            } else {
#ifdef AUTH_MODE_CERT
                Log_d(
                    "dynamic register success, productID: %s, devName: %s, CertFile: "
                    "%s, KeyFile: %s",
                    sDevInfo.product_id, sDevInfo.device_name, sDevInfo.dev_cert_file_name, sDevInfo.dev_key_file_name);
#else
                Log_d(
                    "dynamic register success,productID: %s, devName: %s, "
                    "device_secret: %s",
                    sDevInfo.product_id, sDevInfo.device_name, sDevInfo.device_secret);
#endif
            }
        } else {
            Log_e("%s dynamic register fail", sDevInfo.device_name);
        }
    }

    return ret;
}


static void main_entry1(void *argv)
{
    int        ret;
    DeviceInfo sDevInfo;
    bool       infoNullFlag = false;
    char dev_imei[64] = {0};

    // init log level
    IOT_Log_Set_Level(eLOG_DEBUG);

    memset((char *)&sDevInfo, 0, sizeof(DeviceInfo));
    ret = HAL_GetDevInfo(&sDevInfo);

    ret = ql_dev_get_imei(dev_imei, sizeof(dev_imei));
    Log_d("dev_imei=%s,ret=%d",dev_imei, ret);

#ifndef GATEWAY_ENABLED
    sDevInfo.dev_type = eCOMMON_DEV;
#else
    sDevInfo.dev_type = eGW_SUB_DEV;
#endif

#ifdef AUTH_MODE_CERT
    /* just demo the cert/key files are empty */
    if (!strcmp(sDevInfo.dev_cert_file_name, QCLOUD_IOT_NULL_CERT_FILENAME) ||
        !strcmp(sDevInfo.dev_key_file_name, QCLOUD_IOT_NULL_KEY_FILENAME)) {
        Log_d("dev Cert not exist!");
        infoNullFlag = true;
    } else {
        Log_d("dev Cert exist");
    }
#else
    memset(sDevInfo.device_name, '\0', MAX_SIZE_OF_DEVICE_NAME);
    strncpy(sDevInfo.device_name, dev_imei, MAX_SIZE_OF_DEVICE_NAME);
    Log_d("sDevInfo.device_name=%s",sDevInfo.device_name);
 
    ret = HAL_SetDevInfo(&sDevInfo);
    if (QCLOUD_RET_SUCCESS != ret) {
        Log_e("devices info save fail");
    } 

    #if 0
    Log_d("sDevInfo.device_secret=%s",sDevInfo.device_secret);
    strncpy(sDevInfo.device_secret, QCLOUD_IOT_NULL_DEVICE_SECRET, MAX_SIZE_OF_DEVICE_SECRET);
    Log_d("sDevInfo.device_secret=%s",sDevInfo.device_secret);
    #endif

    /* just demo the PSK is empty */
    if (!strcmp(sDevInfo.device_secret, QCLOUD_IOT_NULL_DEVICE_SECRET)) {
        Log_d("dev psk not exist!");
        infoNullFlag = true;
    } else {
        Log_d("dev psk exist");
    }
#endif

    /* device cert/key files or PSK is empty, do dynamic register to fetch */
    if (infoNullFlag) {
        if (QCLOUD_RET_SUCCESS == IOT_DynReg_Device(&sDevInfo)) {
            ret = HAL_SetDevInfo(&sDevInfo);
            if (QCLOUD_RET_SUCCESS != ret) {
                Log_e("devices info save fail");
            } else {
#ifdef AUTH_MODE_CERT
                Log_d(
                    "dynamic register success, productID: %s, devName: %s, CertFile: "
                    "%s, KeyFile: %s",
                    sDevInfo.product_id, sDevInfo.device_name, sDevInfo.dev_cert_file_name, sDevInfo.dev_key_file_name);
#else
                Log_d(
                    "dynamic register success,productID: %s, devName: %s, "
                    "device_secret: %s",
                    sDevInfo.product_id, sDevInfo.device_name, sDevInfo.device_secret);
#endif
            }
        } else {
            Log_e("%s dynamic register fail", sDevInfo.device_name);
        }
    }

    return ret;
}


int data_call_state=-1;
// static void ql_nw_status_callback(int profile_idx, int nw_status)
// {
// 	Log_i("profile(%d) status: %d", profile_idx, nw_status);
// }
static void ql_data_call_cb(int profile_idx, int nw_status)
{
	Log_i("call_cb: profile%d status=%d\r\n", profile_idx, nw_status);
	data_call_state=nw_status;
}

static int datacall_satrt(void)
{
	struct ql_data_call_info info = {0};
	char ip4_addr_str[16] = {0};
	
	Log_d("wait for network register done");

	if(ql_network_register_wait(120) != 0)
	{
		Log_e("*** network register fail ***");
		return -1;
	}
	else
	{
		Log_d("doing network activating ...");
		
		// ql_wan_start(ql_nw_status_callback);
		ql_set_auto_connect(PROFILE_IDX, TRUE);
        ql_set_data_call_asyn_mode(1, ql_data_call_cb);
		if(ql_start_data_call(PROFILE_IDX, 0, "cmnet", NULL, NULL, 0) == 0)
		{
            while(data_call_state==-1)
			{
				ql_rtos_task_sleep_ms(100);
			}
			ql_get_data_call_info(PROFILE_IDX, 0, &info);
			
			Log_i("info.profile_idx: %d", info.profile_idx);
			Log_i("info.ip_version: %d", info.ip_version);
			Log_i("info.v4.state: %d", info.v4.state);
			Log_i("info.v4.reconnect: %d", info.v4.reconnect);
			
			inet_ntop(AF_INET, &info.v4.addr.ip, ip4_addr_str, sizeof(ip4_addr_str));
			Log_i("info.v4.addr.ip: %s", ip4_addr_str);
			
			inet_ntop(AF_INET, &info.v4.addr.pri_dns, ip4_addr_str, sizeof(ip4_addr_str));
			Log_i("info.v4.addr.pri_dns: %s", ip4_addr_str);
			
			inet_ntop(AF_INET, &info.v4.addr.sec_dns, ip4_addr_str, sizeof(ip4_addr_str));
			Log_i("info.v4.addr.sec_dns: %s", ip4_addr_str);

			return 0;
		}

		Log_e("*** network activated fail ***");
		return -1;
	}
}


int dynreg_dev_sample_start(void)
{
	ql_task_t dynreg_dev_sample_task = NULL;

	if(datacall_satrt() == 0)
		return ql_rtos_task_create(&dynreg_dev_sample_task, 16*1024, 100, "dynreg_dev_sample", main_entry1, NULL);

	return -1;
}

// application_init(dynreg_dev_sample_start, "dynreg_dev_sample_start", 30, 0);